/*-+-*****************************************************************************
 Copyright (C) 2009-2012 Oceanside Software Corporation (R)
 Dallas, Texas

 Author       : Jason T. Brower
 Purpose      : This file is part of a point-of-sale software package
                originally written for Table-Service Restaurants.
              
 Date         : July 8th of 2012
              
 History      : The application that this software file belongs to was 
                written over a 3-Year period.  The first version was written
                in C# .Net 3.5 using Windows Forms.  Being new to .Net at
                the time, I soon learned of Windows Presentation Foundation,
                liked the graphics capabilities and databinding so I
                migrated to WPF.  When the .Net 4.0 framework was released
                the application was migrated from 3.5 to 4.0. Now today,
                .Net 4.5 RC is out and I was already in process of migrating
                before I made this public.
                
Excuse Me     : Please excuse the coding style, it is not representative of
                my typical work.  During the three years I was under a very
                tight budget, constantly running out of funding and was 
                working 18 hour days hyped up on 5-Hour Energy.  The 
                design is not textbook.  It is monolythic because of
                previous issues I will not get into.  There are few comments
                in the code and the ones that are there may be incorrect.
                
What it is not: This is not the exact version that I took through PA-DSS 2.0
                nor is it the exact version running at my customer sites.
                I removed some details for security purposes including some
                encryption algorithms.  The reporting was removed because
                I was including a third party library that cannot be 
                published with this Open Source.
                
What it is    : This application has been running at high volume restaraunts
                for over a year.  It never freezes, crashes or does anything
                unexpected.  So long as it is built, installed and configured
                correctly, it is a strong system that we can all enhance.

Contact       : Please note that I can no longer work for free.  However, you
                can reach me at information@oceansidesw.com.                                                      

*********************************************************************************/
using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
#if _LOCALDB
using Oceanside.LocalDB;
#else
using Oceanside.RemoteDB;
#endif

#if _LOCALDB
namespace Oceanside.LocalDB
#else
namespace Oceanside.RemoteDB
#endif
{
    /// <summary>
    /// A kiosk is a terminal (kiosk) that the user uses to enter data into the system via a touchscreen.
    /// </summary>
    public partial class KIOSK
    {
        const int CONST_HOSTNAME_INVALID = -1;
        #region Public Static Functions

        public static int _cachedHostNumber = CONST_HOSTNAME_INVALID;
        public static string _cachedHostName = null;

        public static List<KIOSK> GetAll()
        {
            List<KIOSK> allKiosks = null;
            try
            {
                var q = from KIOSK in SHIFT.GlobalContext.KIOSKS where KIOSK.IsDeleted == false select KIOSK;

                if (q.Any())
                {
                    allKiosks = q.ToList();
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
            return allKiosks;
        }

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public static decimal GetCashDrawerAmount()
        {
            decimal amount = 0M;
            try
            {
                KIOSK k = KIOSK.Get(SHIFT.GlobalContext);
                BUSINESS_DAY bd = BUSINESS_DAY.GetNow(SHIFT.GlobalContext);
                if (bd != null)
                {
                    ///Get the amount of cash transactions on this terminal
                    var transactions = SHIFT.GlobalContext.TRANSACTIONS.Where(t => t.BusinessDayId == bd.Id &&
                        t.TransactionType == TRANSACTION.CONST_PAY_CASH && t.TerminalId == k.Id);

                    if (transactions.Count() != 0)
                    {
                        amount = transactions.Sum(t => t.Base);
                    }

                    var piQ = SHIFT.GlobalContext.PAYMENTS.Where(p => p.SHIFT.NavBusinessDayId == bd.Id && p.WasPaidIn);
                    decimal paidInTotal = 0;
                    if (piQ.Any())
                    {
                        paidInTotal = piQ.Sum(p => p.Amount);
                    }

                    var poQ = SHIFT.GlobalContext.PAYMENTS.Where(p => p.SHIFT.NavBusinessDayId == bd.Id && !p.WasPaidIn);
                    decimal paidOutTotal = 0;
                    if (poQ.Any())
                    {
                        paidOutTotal = poQ.Sum(p => p.Amount);
                    }

                    amount += paidInTotal;
                    amount -= paidOutTotal;

                    var dayStarQ = SHIFT.GlobalContext.DEPOSITS.Where(d => d.BUSINESS_DAY.Id == bd.Id && d.Amount > 0);
                    decimal cashStart = 0;
                    if (dayStarQ.Any())
                    {
                        cashStart = dayStarQ.Sum(p => p.Amount);
                    }

                    var cashDropsQ = SHIFT.GlobalContext.DEPOSITS.Where(d => d.BUSINESS_DAY.Id == bd.Id && d.Amount < 0);
                    decimal cashDrops = 0;
                    if (cashDropsQ.Any())
                    {
                        cashDrops = cashDropsQ.Sum(p => p.Amount);
                    }

                    amount += cashStart;
                    amount += cashDrops; ///Cash Drop amounts are negative.
                }
            }
            catch (Exception ex)
            {
                Logging.LogException(ex);
            }
            return amount;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fromStore"></param>
        /// <returns></returns>
        public static KIOSK Get(DominicaEntities context)
        {
            KIOSK kiosk = null;
            try
            {
                string hostName = KIOSK.Hostname();
                if (!String.IsNullOrEmpty(hostName))
                {
                    var q = from k in context.KIOSKS
                            where k.IsDeleted == false && k.Name == hostName
                            select k;

                    if (q.Any())
                    {
                        kiosk = q.First();
                    }
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
            return kiosk;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static AUTO_GRATUITY GetActiveAutoGratuity(int partyCount)
        {
            KIOSK kiosk = KIOSK.Get(SHIFT.GlobalContext);

            if (kiosk != null && kiosk.AUTO_GRATUITYS.Count() != 0)
            {
                foreach (AUTO_GRATUITY ag in kiosk.AUTO_GRATUITYS)
                {
                    if (partyCount >= ag.AutoGratuitySeatStartCount)
                    {
                        DateTime rightNow = DateTime.Now;
                        DayOfWeek dow = rightNow.DayOfWeek;

                        if (dow == DayOfWeek.Monday)
                        {
                            if (ag.RunMonday)
                            {
                                DateTime startTime = ag.MondayStartTime;
                                DateTime endTime = ag.MondayEndTime;
                                if (Functions.IsInBetweenTimeFrame(rightNow, startTime, endTime))
                                {
                                    return ag;
                                }
                            }
                        }
                        else if (dow == DayOfWeek.Tuesday)
                        {
                            if (ag.RunTuesday)
                            {
                                DateTime startTime = ag.TuesdayStartTime;
                                DateTime endTime = ag.TuesdayEndTime;
                                if (Functions.IsInBetweenTimeFrame(rightNow, startTime, endTime))
                                {
                                    return ag;
                                }
                            }
                        }
                        else if (dow == DayOfWeek.Wednesday)
                        {
                            if (ag.RunWednesday)
                            {
                                DateTime startTime = ag.WednesdayStartTime;
                                DateTime endTime = ag.WednesdayEndTime;
                                if (Functions.IsInBetweenTimeFrame(rightNow, startTime, endTime))
                                {
                                    return ag;
                                }
                            }
                        }
                        else if (dow == DayOfWeek.Thursday)
                        {
                            if (ag.RunThursday)
                            {
                                DateTime startTime = ag.ThursdayStartTime;
                                DateTime endTime = ag.ThursdayEndTime;
                                if (Functions.IsInBetweenTimeFrame(rightNow, startTime, endTime))
                                {
                                    return ag;
                                }
                            }
                        }
                        else if (dow == DayOfWeek.Friday)
                        {
                            if (ag.RunFriday)
                            {
                                DateTime startTime = ag.FridayStartTime;
                                DateTime endTime = ag.FridayEndTime;
                                if (Functions.IsInBetweenTimeFrame(rightNow, startTime, endTime))
                                {
                                    return ag;
                                }
                            }
                        }
                        else if (dow == DayOfWeek.Saturday)
                        {
                            if (ag.RunSaturday)
                            {
                                DateTime startTime = ag.SaturdayStartTime;
                                DateTime endTime = ag.SaturdayEndTime;
                                if (Functions.IsInBetweenTimeFrame(rightNow, startTime, endTime))
                                {
                                    return ag;
                                }
                            }
                        }
                        else if (dow == DayOfWeek.Sunday)
                        {
                            if (ag.RunSunday)
                            {
                                DateTime startTime = ag.SundayStartTime;
                                DateTime endTime = ag.SundayEndTime;
                                if (Functions.IsInBetweenTimeFrame(rightNow, startTime, endTime))
                                {
                                    return ag;
                                }
                            }
                        }
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static decimal GetNodeAutoGratuityAmount(decimal entireTableSubtotal, decimal paidSubtotal, AUTO_GRATUITY ag)
        {
            decimal amount = 0.00M;
            KIOSK kiosk = KIOSK.Get(SHIFT.GlobalContext);

            if (ag != null)
            {
                decimal programmedRate = ag.AutoGratuityRate / 100M;

                ///Node get the percentage of the entire tables subtotal vs. what was actually paid.
                if (entireTableSubtotal > 0M)
                {
                    if (paidSubtotal != 0)
                    {
                        decimal paidPercent = (paidSubtotal / entireTableSubtotal);
                        amount = (paidPercent * entireTableSubtotal) * programmedRate;
                        amount = Math.Round(amount, 2, MidpointRounding.AwayFromZero);
                    }
                    else
                    {
                        amount = entireTableSubtotal * programmedRate;
                        amount = Math.Round(amount, 2, MidpointRounding.AwayFromZero);
                    }
                }
            }
            return amount;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static string GetLocalHostName()
        {
            System.Net.IPHostEntry ip = System.Net.Dns.GetHostEntry("localhost");
            return ip.HostName;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fromStore"></param>
        /// <returns></returns>
        public static string Hostname()
        {
            if (String.IsNullOrEmpty(_cachedHostName))
            {
                _cachedHostName = GetLocalHostName();
            }
            return _cachedHostName;
        }

        public static string GetKioskNameForId(Int64 id)
        {
            string name = "";
            try
            {
                List<KIOSK> klist = KIOSK.GetAll();
                var q = from K in klist where K.Id == id select K;
                if (q.Any())
                {
                    name = q.First().Name;
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
            return name;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static bool CanLaunch()
        {
            var q = from USER in SHIFT.GlobalContext.USERS.Include("ROLES.ACCESS_LEVEL")
                        .Include("ROLES.PAYGRADE")
                        .Include("ROLES.JOB_CODE")
                        .Include("ROLES.JOB_CODE")
                    where USER.IsTerminated == false
                    select USER;

            if (!q.Any())
            {
                return false;
            }

            var q1 = from SYSCONFIG in SHIFT.GlobalContext.SYSCONFIGS select SYSCONFIG;

            if (!q1.Any())
            {
                return false;
            }

            if (!VerifyHostNameFormat(_cachedHostName))
            {
                return false;
            }

            if (KIOSK.Get(SHIFT.GlobalContext) == null)
            {
                return false;
            }

            DAYPART daypart = DAYPART.GetDefaultDaypart(SHIFT.GlobalContext);
            if (daypart == null)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Indicated if we have a local printer attached to this kiosk.
        /// </summary>
        /// <returns></returns>
        public static bool HasLocalPrinter()
        {
            if (SHIFT.GlobalContext != null)
            {
                KIOSK kiosk = KIOSK.Get(SHIFT.GlobalContext);
                if (kiosk != null && kiosk.LocalPrinterId != 0 && kiosk.LocalPrinterId != null)
                {
                    return true;
                }
            }
            return false;
        }

        public static int HostNumber(bool fromStore = false)
        {
            if (CONST_HOSTNAME_INVALID == _cachedHostNumber)
            {
                ///Will verify and set the hostname
                VerifyHostNameFormat(KIOSK.Hostname());
            }
            return _cachedHostNumber;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static bool VerifyHostNameFormat(string name)
        {
#if !_LOCALDB
            bool foundHostInt = false;

            ///If we have an error here, there is not much we can do.  We just need to make sure the
            ///user interface presents it to the user.
            try
            {
                string hostName = KIOSK.Hostname();
                if (!string.IsNullOrEmpty(hostName) && hostName.Contains('-'))
                {
                    int idx = hostName.IndexOf('-');
                    if ((idx + 1) < hostName.Length)
                    {
                        string sub = hostName.Substring(idx + 1);

                        try
                        {
                            _cachedHostNumber = Convert.ToByte(sub);
                            foundHostInt = true;
                        }
                        catch
                        {
                            ///Just for clarity
                            foundHostInt = false;
                        }
                    }
                }
            }
            catch
            {
                ///For clarity.
                foundHostInt = false;
            }

            return foundHostInt;
#else
            return true;
#endif
        }
        #endregion Public Static Functions
    }
}
